#ifndef __GAME_SAFE_STACK_HPP__
#define __GAME_SAFE_STACK_HPP__

#include <vector>
#include <cstdint>
#include <mutex>
#include "GameLock.hpp"

template <typename T>
class GameSafeStack
{
private:
    std::vector<T> m_memoryVec;
    int32_t m_index = 0;
    SpinLock m_lock;

public:
    inline void setSize(int32_t size)
    {
        m_lock.lock();
        m_memoryVec.reserve(size);
        m_lock.unlock();
    }

    inline int32_t getSourceSize()
    {
        std::lock_guard<SpinLock> lk(m_lock);
        return (int32_t)m_memoryVec.size();
    }

    inline int32_t getStackSize()
    {
        std::lock_guard<SpinLock> lk(m_lock);
        return m_index;
    }

    inline void clear()
    {
        m_lock.lock();
        m_index = 0;
        m_lock.unlock();
    }

    inline bool empty()
    {
        std::lock_guard<SpinLock> lk(m_lock);
        return 0 == m_index;
    }

    inline void push(const T &t)
    {
        m_lock.lock();

        if (m_index < m_memoryVec.size())
        {
            m_memoryVec[m_index] = t;
        }
        else
        {
            m_memoryVec.push_back(t);
        }
        ++m_index;

        m_lock.unlock();
    }

    inline void pop()
    {
        m_lock.lock();

        if (m_index > 0)
        {
            --m_index;
        }

        m_lock.unlock();
    }
    T &top() 
    {
        std::lock_guard<SpinLock> lk(m_lock);
        return m_memoryVec[m_index - 1]; 
    }
    const T &top() const 
    {
        std::lock_guard<SpinLock> lk(m_lock);
        return m_memoryVec[m_index - 1];
    }

    inline std::vector<T>& source()
    {
        std::lock_guard<SpinLock> lk(m_lock);
        return this->m_memoryVec;
    }

    inline void setIndex(int32_t index)
    {
        std::lock_guard<SpinLock> lk(m_lock);
        m_index = index;
    }
};

#endif